using System;
using System.Collections.Generic;
using System.Text;

namespace NBear.Common
{
    public class PropertyItem
    {
        private string columnName;
        private string leftToken = "[|";
        private string rightToken = "|]";
        private string paramPrefix = "[-@-]";

        internal string ColumnName
        {
            get
            {
                return leftToken + columnName + rightToken;
            }
        }

        internal string ParamName
        {
            get
            {
                return paramPrefix + columnName + "_" + Guid.NewGuid().ToString("N") + " ";
            }
        }

        public OrderByClip Asc
        {
            get
            {
                return new OrderByClip(this, false);
            }
        }

        public OrderByClip Desc
        {
            get
            {
                return new OrderByClip(this, true);
            }
        }

        public PropertyItem(string columnName, string leftToken, string rightToken, string paramPrefix)
        {
            this.columnName = columnName;
            this.leftToken = leftToken;
            this.rightToken = rightToken;
            this.paramPrefix = paramPrefix;
        }

        public PropertyItem(string propertyName)
        {
            this.columnName = propertyName;
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }

        #region Equals and Not Equals

        public static WhereClip operator ==(PropertyItem left, PropertyItem right)
        {
            return new WhereClip(left.ColumnName + " = " + right.ColumnName);
        }

        public static WhereClip operator !=(PropertyItem left, PropertyItem right)
        {
            return new WhereClip(left.ColumnName + " <> " + right.ColumnName);
        }

        public static WhereClip operator ==(PropertyItem left, object right)
        {
            return new WhereClip(left.ColumnName + " = " + left.ParamName, right);
        }

        public static WhereClip operator !=(PropertyItem left, object right)
        {
            return new WhereClip(left.ColumnName + " <> " + left.ParamName, right);
        }

        public static WhereClip operator ==(object left, PropertyItem right)
        {
            return new WhereClip(right.ParamName + " = " + right.ColumnName, left);
        }

        public static WhereClip operator !=(object left, PropertyItem right)
        {
            return new WhereClip(right.ParamName + " <> " + right.ColumnName, left);
        }

        #endregion

        #region Greater and Less

        public static WhereClip operator >(PropertyItem left, PropertyItem right)
        {
            return new WhereClip(left.ColumnName + " > " + right.ColumnName);
        }

        public static WhereClip operator <(PropertyItem left, PropertyItem right)
        {
            return new WhereClip(left.ColumnName + " < " + right.ColumnName);
        }

        public static WhereClip operator >(PropertyItem left, object right)
        {
            return new WhereClip(left.ColumnName + " > " + left.ParamName, right);
        }

        public static WhereClip operator <(PropertyItem left, object right)
        {
            return new WhereClip(left.ColumnName + " < " + left.ParamName, right);
        }

        public static WhereClip operator >(object left, PropertyItem right)
        {
            return new WhereClip(right.ParamName + " > " + right.ColumnName, left);
        }

        public static WhereClip operator <(object left, PropertyItem right)
        {
            return new WhereClip(right.ParamName + " < " + right.ColumnName, left);
        }

        #endregion

        #region Greater or Equals and Less and Equals

        public static WhereClip operator >=(PropertyItem left, PropertyItem right)
        {
            return new WhereClip(left.ColumnName + " >= " + right.ColumnName);
        }

        public static WhereClip operator <=(PropertyItem left, PropertyItem right)
        {
            return new WhereClip(left.ColumnName + " <= " + right.ColumnName);
        }

        public static WhereClip operator >=(PropertyItem left, object right)
        {
            return new WhereClip(left.ColumnName + " >= " + left.ParamName, right);
        }

        public static WhereClip operator <=(PropertyItem left, object right)
        {
            return new WhereClip(left.ColumnName + " <= " + left.ParamName, right);
        }

        public static WhereClip operator >=(object left, PropertyItem right)
        {
            return new WhereClip(right.ParamName + " >= " + right.ColumnName, left);
        }

        public static WhereClip operator <=(object left, PropertyItem right)
        {
            return new WhereClip(right.ParamName + " <= " + right.ColumnName, left);
        }

        #endregion

        #region Like

        public WhereClip Like(string right)
        {
            return new WhereClip(this.ColumnName + " LIKE " + this.ParamName, right);
        }

        #endregion

        #region Static Members

        public static string ParseExpressionByMetaData(string inStr, PropertyToColumnMapHandler propertyToColumnMapHandler, string leftToken, string rightToken, string paramPrefix)
        {
            string retStr = inStr;

            System.Text.RegularExpressions.Regex r = new System.Text.RegularExpressions.Regex(@"\[\|[\w\d_]+\|\]", System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.Multiline);
            System.Text.RegularExpressions.MatchCollection ms = r.Matches(retStr);
            foreach (System.Text.RegularExpressions.Match m in ms)
            {
                retStr = retStr.Replace(m.Value, string.Format("{0}{1}{2}", leftToken, propertyToColumnMapHandler(m.Value.Trim('[', ']', '|')), rightToken));
            }

            r = new System.Text.RegularExpressions.Regex(@"\[-@-\][\w\d_]+\s+", System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.Multiline);
            ms = r.Matches(retStr);
            foreach (System.Text.RegularExpressions.Match m in ms)
            {
                retStr = retStr.Replace(m.Value, string.Format("{0}{1} ", paramPrefix, m.Value.Replace("[-@-]", "")));
            }

            return retStr;
        }

        #endregion
    }

    public class ProcedureParamItem
    {
        private string name;

        public string Name
        {
            get
            {
                return name;
            }
        }

        public ProcedureParamItem(string name)
        {
            this.name = name;
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }

        #region Equals and Not Equals

        public static WhereClip operator ==(ProcedureParamItem left, object right)
        {
            return new WhereClip(left.Name + " = @" + left.Name, right);
        }

        public static WhereClip operator !=(ProcedureParamItem left, object right)
        {
            return new WhereClip(left.Name + " <> @" + left.Name, right);
        }

        #endregion

    }

    public class WhereClip
    {
        private string whereStr;
        private object[] paramValues;

        public object[] ParamValues
        {
            get
            {
                if (paramValues == null)
                {
                    return new object[0];
                }
                else
                {
                    return paramValues;
                }
            }
        }

        public WhereClip(string whereStr, params object[] paramValues)
        {
            this.whereStr = whereStr;
            this.paramValues = paramValues;
        }

        public override string ToString()
        {
            return whereStr;
        }

        #region Operators

        public static WhereClip operator &(WhereClip left, WhereClip right)
        {
            string where = "(" + left.ToString() + ")" + " AND " + "(" + right.ToString() + ")";
            object[] values = new object[left.ParamValues.Length + right.ParamValues.Length];
            left.ParamValues.CopyTo(values, 0);
            right.ParamValues.CopyTo(values, left.ParamValues.Length);

            return new WhereClip(where, values);
        }

        public static WhereClip operator |(WhereClip left, WhereClip right)
        {
            string where = "(" + left.ToString() + ")" + " OR " + "(" + right.ToString() + ")";
            object[] values = new object[left.ParamValues.Length + right.ParamValues.Length];
            left.ParamValues.CopyTo(values, 0);
            right.ParamValues.CopyTo(values, left.ParamValues.Length);

            return new WhereClip(where, values);
        }

        public static WhereClip operator !(WhereClip right)
        {
            return new WhereClip("Not " + "(" + right.ToString() + ")", right.paramValues);
        }

        #endregion
    }

    public class OrderByClip
    {
        private string orderByStr;

        public override string ToString()
        {
            return orderByStr;
        }

        public OrderByClip(PropertyItem item, bool descend)
        {
            if (descend)
            {
                this.orderByStr = item.ColumnName + " DESC";
            }
            else
            {
                this.orderByStr = item.ColumnName;
            }
        }

        public OrderByClip(string orderByStr)
        {
            this.orderByStr = orderByStr;
        }

        public static OrderByClip operator &(OrderByClip left, OrderByClip right)
        {
            return new OrderByClip(left.ToString() + ", " + right.ToString());
        }
    }

    public delegate string PropertyToColumnMapHandler(string propertyName);
}
